package com.zx.account.service.impl;

import com.zx.account.controller.vo.AccountVo;
import com.zx.account.dao.AccountMapper;
import com.zx.account.entity.Account;
import com.zx.account.model.ATypeDetailDto;
import com.zx.account.model.ATypeDto;
import com.zx.account.model.BurnChartDto;
import com.zx.account.model.MonthAccountDto;
import com.zx.account.model.YearAccountDto;
import com.zx.account.model.query.AccountQuery;
import com.zx.account.service.ATypeService;
import com.zx.account.service.AccountService;
import com.zx.account.service.MonthService;
import com.zx.util.BeanCopyUtil;
import com.zx.util.DateUtil;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

@Slf4j
@Service
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountMapper accountMapper;

    @Autowired
    private MonthService monthService;

    @Autowired
    private ATypeService aTypeService;

    @Override
    @Transactional
    public boolean insert(Account acc) {
        log.info("AccountService#insert account={}", acc);
        int insert = accountMapper.insert(acc);
        // 判断是否需要创建年月表
        if (insert > 0) {
            LocalDate localDate = DateUtil.UDateToLocalDate(acc.getConsumeDate());
            if (this.monthService.getEmpty(localDate.getYear(), localDate.getMonthValue(), acc.getUserId())) {
                this.monthService.insert(localDate.getYear(), localDate.getMonthValue(), acc.getUserId());
            }
        } else {
            return false;
        }
        return true;
    }

    @Override
    public Account getById(int id) {
        log.info("AccountService#getById accountId={}", id);
        return accountMapper.selectById(id);
    }

    @Override
    public boolean delete(int id) {
        log.info("AccountService#delete accountId={}", id);
        return accountMapper.deleteById(id) > 0;
    }

    @Override
    public List<AccountVo> getAccount(Date beginDate, Date endDate, int tid, Integer tdId, int userId) {
        log.info("AccountService#getAccount beginDate={} endDate={} tid={} tdId={}, userId={}", beginDate, endDate, tid,
                tdId, userId);
        AccountQuery query = new AccountQuery().setBeginDate(beginDate)
                .setEndDate(endDate)
                .setTId(tid)
                .setTDId(tdId)
                .setUserId(userId);
        List<Account> queryData = this.accountMapper.selectByQuery(query);
        return this.fillTypeName(queryData, userId);
    }

    @Override
    public List<AccountVo> getByMonth(int year, int month, int userId) {
        log.info("AccountService#getAccount month={} userId={}", month, userId);
        AccountQuery query = new AccountQuery().setYear(year).setMonth(month).setUserId(userId);
        List<Account> queryData = this.accountMapper.selectByQuery(query);
        return this.fillTypeName(queryData, userId);
    }

    /**
     * @param li
     * @Title: 填充消费记录中的消费类型
     * @date: 2019年10月5日下午5:43:42
     * @author: zhangxue
     */
    private List<AccountVo> fillTypeName(List<Account> li, int userId) {
        if (CollectionUtils.isEmpty(li)) {
            return Collections.emptyList();
        }

        List<AccountVo> resList = BeanCopyUtil.copy(li, Account.class, AccountVo.class);

        log.info("AccountService#fillTypeName li.size={}", li.size());
        List<ATypeDto> types = this.aTypeService.getByUserId(userId);
        List<ATypeDetailDto> typeDetails = this.aTypeService.getDetailByUserId(userId);
        Map<Integer, ATypeDto> typeMap = types.stream().collect(Collectors.toMap(ATypeDto::getId, t -> t));
        Map<Integer, ATypeDetailDto> typeDetailMap = typeDetails.stream()
                .collect(Collectors.toMap(ATypeDetailDto::getId, t -> t));
        for (AccountVo vo : resList) {
            Integer tId = vo.getTId();
            ATypeDto aType = typeMap.get(tId);
            // 数据库也不存在的话就创建一个临时的，防止多次查询数据
            if (aType == null) {
                aType = new ATypeDto().setId(tId).setName("类型不存在");
                typeMap.put(tId, aType);
            }
            vo.setTypeName(aType.getName());

            Integer tdId = vo.getTDId();
            if (tdId == null || tdId == 0) {
                vo.setTypeDetailName("无");
                continue;
            }

            ATypeDetailDto detailDto = typeDetailMap.get(tdId);
            if (detailDto == null) {
                detailDto = new ATypeDetailDto().setId(tId).setName("详情不存在");
                typeDetailMap.put(tId, detailDto);
            }
            vo.setTypeDetailName(detailDto.getName());
        }

        // 按时间分组，用于填充单元格
        Map<Long, List<AccountVo>> timeMap = resList.stream()
                .collect(Collectors.groupingBy(acc -> acc.getConsumeDate().getTime()));

        for (Entry<Long, List<AccountVo>> entry : timeMap.entrySet()) {
            // 每日的消费
            List<AccountVo> subList = entry.getValue();

            Optional<BigDecimal> reduce = subList.stream()
                    .map(AccountVo::getPrice)
                    .reduce(BigDecimal::add);

            BigDecimal daySum = reduce.orElse(BigDecimal.ZERO);
            subList.get(0).setPriceForDateSum(daySum);
            subList.get(0).setColspan(1);
            subList.get(0).setRowspan(subList.size());
        }

        return resList;
    }

    @Override
    public List<MonthAccountDto> getMonthAccount(int year, int[] tids, int userId) {
        log.info("getMonthAccount year={} tids={} userId={}", year, Arrays.toString(tids), userId);
        AccountQuery query = new AccountQuery().setYear(year).setTIds(tids).setUserId(userId);
        return this.accountMapper.selectMonthAccount(query);
    }

    @Override
    public List<YearAccountDto> getYearAccount(int beginYear, int endYear, int[] tids, int userId) {
        log.info("getYearAccount beginYear={} endYear={} tids={}, userId={}",
                beginYear, endYear, Arrays.toString(tids), userId);

        Calendar begin = Calendar.getInstance();
        begin.set(beginYear, 1, 1);

        Calendar end = Calendar.getInstance();
        end.set(endYear, 12, 31);

        Date beginDate = cn.hutool.core.date.DateUtil.beginOfYear(begin).getTime();
        Date endDate = cn.hutool.core.date.DateUtil.endOfYear(end).getTime();

        AccountQuery query = new AccountQuery()
                .setBeginDate(beginDate)
                .setEndDate(endDate)
                .setTIds(tids)
                .setUserId(userId);

        return this.accountMapper.selectYearAccount(query);
    }

    @Override
    public List<BurnChartDto> getBurnDataByType(int[] tids, int year, int month, int userId) {
        Date begin = DateUtil.LocalDateToUdate(LocalDate.of(year, month, 1));
        // 校验并修正月与年
        month = month + 1;
        year = month > 12 ? year + 1 : year;
        month = month > 12 ? month - 12 : month;
        Date end = DateUtil.LocalDateToUdate(LocalDate.of(year, month, 1));

        AccountQuery query = new AccountQuery().setBeginDate(begin).setEndDate(end).setTIds(tids).setUserId(userId);

        List<BurnChartDto> data = this.accountMapper.selectBurnDataByType(query);
        data.stream().forEach(x -> {
            Integer week = Integer.parseInt(x.getWeek());
            week = week == 1 ? 7 : week - 1;
            x.setWeek(week.toString());
        });
        return data;
    }

}
